//
//  LinkedListView.swift
//  DataStructure
//
//  Created by kys-20 on 2019/8/27.
//  Copyright © 2019 kys-20. All rights reserved.
//


enum TypeOfLine {
    case LabelSlashLine
    case LabelAndLabelLine
}



import Foundation
import UIKit
class LinkedListView : UIView{
    
    let textField = UITextField()//输入框
    let buttonEnqueue = UIButton()//入列按钮
    let buttonDequeue = UIButton()//出列按钮
    let buttonClearQueue = UIButton()//清除队列按钮
    let slider = UISlider()//滑块 用来控制时间
    let headTextLabel = UILabel()
    let tailTextLabel = UILabel()
    let headLabel = UILabel()
    let tailLabel = UILabel()
    let viLine = UIView()
    let labelMark = UILabel()//用来标识是进队出对
    let labelValue = UILabel()//用来展示进队出对的值
    var unitDistanceX : Double = 0.0//单位距离 根据总时间和总距离所得
    var unitDistanceY : Double = 0.0//单位距离 根据总时间和总距离所得
    
    
    var sumTime : Double = 2.00 // 总时间
    //    label中的斜线
    var slashPathArray = [UIBezierPath]()
    var slashShapeLayerArray = [CAShapeLayer]()
    //    label连接线
    var pathArray = [UIBezierPath]()
    var shapeLayerArray = [CAShapeLayer]()
    var headSubscript = 0
    var tailSubscript = 0
    var timeOne : Timer!//计时器
    var numTimeOne : Double = 0.00
    var timeTwo : Timer!//控制按钮是否可点击的计时器
    var numTimeTwo : Double = 0.00
    
    var queueLabelArray = [CustomLabel]()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        viLine.frame = self.frame
        self.addSubview(viLine)
        setUpUI()
    }
    
    //   初始界面
    func setUpUI(){
        slider.frame = CGRect(x: 10, y: UIScreen.main.bounds.height-200, width: UIScreen.main.bounds.width-20, height: 30)
        slider.minimumValue = 0
        slider.maximumValue = 4
        slider.value = 2.00
        self.addSubview(slider)
        slider.isContinuous = false//滑块滑动停止后才触发ValueChanged事件
        slider.addTarget(self, action: #selector(ActionSliderValueChange), for: .valueChanged)
        
        textField.frame = CGRect(x: 20, y: 35, width: 70, height: 40)
        textField.borderStyle = .roundedRect
        textField.layer.borderColor = UIColor.red.cgColor
        textField.layer.borderWidth = 1
        self.addSubview(textField)
        buttonEnqueue.frame = CGRect(x: 100, y: 35, width: 70, height: 40)
        buttonEnqueue.setTitle("Enqueue", for: .normal)
        buttonEnqueue.titleLabel?.font = UIFont.systemFont(ofSize: 15)
        buttonEnqueue.setTitleColor(UIColor.black, for: .normal)
        buttonEnqueue.backgroundColor = UIColor.white
        buttonEnqueue.layer.borderWidth = 1
        self.addSubview(buttonEnqueue)
        buttonEnqueue.addTarget(self, action: #selector(ActionButtonEnqueue), for: .touchUpInside)
        
        buttonDequeue.frame = CGRect(x: 180, y: 35, width: 70, height: 40)
        buttonDequeue.setTitle("Dequeue", for: .normal)
        buttonDequeue.titleLabel?.font = UIFont.systemFont(ofSize: 15)
        buttonDequeue.setTitleColor(UIColor.black, for: .normal)
        buttonDequeue.backgroundColor = UIColor.white
        buttonDequeue.layer.borderWidth = 1
        buttonDequeue.addTarget(self, action: #selector(ActionDequeue), for: .touchUpInside)
        self.addSubview(buttonDequeue)
        
        buttonClearQueue.frame = CGRect(x: 260, y: 35, width: 100, height: 40)
        buttonClearQueue.setTitle("Clear Queue", for: .normal)
        buttonClearQueue.titleLabel?.font = UIFont.systemFont(ofSize: 15)
        buttonClearQueue.setTitleColor(UIColor.black, for: .normal)
        buttonClearQueue.backgroundColor = UIColor.white
        buttonClearQueue.layer.borderWidth = 1
        buttonClearQueue.addTarget(self, action: #selector(ActionClearQueue), for: .touchUpInside)
        self.addSubview(buttonClearQueue)
        
        headTextLabel.frame = CGRect(x: 30, y: 170, width: 60, height: 60)
        headTextLabel.text = "Head"
        headTextLabel.textColor = UIColor.black
        headTextLabel.textAlignment = .center
        self.addSubview(headTextLabel)
        
        headLabel.frame = CGRect(x: 90, y: 170, width: 50, height: 50)
        headLabel.layer.masksToBounds = true
        headLabel.layer.borderWidth = 1
        headLabel.layer.borderColor = UIColor.black.cgColor
        self.addSubview(headLabel)
        
        tailTextLabel.frame = CGRect(x: 30, y: UIScreen.main.bounds.height-280, width: 50, height: 50)
        tailTextLabel.text = "Tail"
        tailTextLabel.textColor = UIColor.black
        tailTextLabel.textAlignment = .center
        self.addSubview(tailTextLabel)
        
        tailLabel.frame = CGRect(x: 90, y: UIScreen.main.bounds.height-280, width: 50, height: 50)
        tailLabel.layer.masksToBounds = true
        tailLabel.layer.borderWidth = 1
        tailLabel.layer.borderColor = UIColor.black.cgColor
        self.addSubview(tailLabel)
        
        labelMark.frame = CGRect(x: 20, y: 90, width: 120, height: 20)
        labelMark.font = UIFont.systemFont(ofSize: 15)
        labelMark.textColor = UIColor.black
        labelMark.textAlignment = .center
        labelMark.isHidden = true
        self.addSubview(labelMark)
        
        labelValue.frame = CGRect(x: 130, y: 90, width: 80, height: 20)
        labelValue.textColor = UIColor.black
        labelValue.textAlignment = .left
        labelValue.isHidden = true
        self.addSubview(labelValue)
        
        setUpSlash(type: .LabelSlashLine)
        setUpSlash(type: .LabelSlashLine)
        setUpSlash(type: .LabelSlashLine)
        
        setPointOfLine(path: slashPathArray[0], shapeLayer: slashShapeLayerArray[0], move: CGPoint(x: headLabel.frame.minX, y: headLabel.frame.minY), addLine: CGPoint(x: headLabel.frame.maxX, y: headLabel.frame.maxY))
        setPointOfLine(path: slashPathArray[1], shapeLayer: slashShapeLayerArray[1], move: CGPoint(x: tailLabel.frame.minX, y: tailLabel.frame.minY), addLine: CGPoint(x: tailLabel.frame.maxX, y: tailLabel.frame.maxY))
        
    }


    //    选择创建视图  斜线
    func setUpSlash(type:TypeOfLine){
        let path = UIBezierPath()
        let shapeLayer = CAShapeLayer()
        path.move(to: CGPoint(x: 0, y: 0))
        path.addLine(to: CGPoint(x: 0, y: 0))
        path.close()
        
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.lineWidth = 1
        shapeLayer.lineJoin = CAShapeLayerLineJoin.round
        shapeLayer.lineCap = CAShapeLayerLineCap.round
        shapeLayer.path = path.cgPath
        shapeLayer.strokeStart = 0
        shapeLayer.strokeEnd = 1
        
        switch type {
        case .LabelAndLabelLine:
            shapeLayer.strokeColor = UIColor.red.cgColor
            shapeLayerArray.append(shapeLayer)
            pathArray.append(path)
        default:
            shapeLayer.strokeColor = UIColor.black.cgColor
            slashShapeLayerArray.append(shapeLayer)
            slashPathArray.append(path)
        }
        viLine.layer.addSublayer(shapeLayer)
    }
    //    绘制线条的始末坐标-------------------------------------------------------------
    func setPointOfLine(path:UIBezierPath,shapeLayer:CAShapeLayer,move:CGPoint,addLine:CGPoint){
        path.removeAllPoints()
        path.move(to: move)
        path.addLine(to: addLine)
        shapeLayer.path = path.cgPath
    }
    //    入队动画-------------------------------------------------------------------
    @objc func ActionButtonEnqueue(){
        if textField.text != ""{
            setQueueLabel()
            textField.text = ""
            buttonIsEnabledFalse()
        }
        
    }
    let labelWDITH  = (UIScreen.main.bounds.width - 100)/4
    func setQueueLabel(){
        
        tailSubscript = tailSubscript + 1
        
        let label = CustomLabel()
        label.frame = CGRect(x: 180, y: 100, width: labelWDITH, height: labelWDITH/2)
        self.addSubview(label)
        queueLabelArray.append(label)
        setPointOfLine(path: slashPathArray[2], shapeLayer: slashShapeLayerArray[2], move: CGPoint(x: label.frame.origin.x + label.frame.width*(3/4), y: label.frame.origin.y), addLine: CGPoint(x: label.frame.maxX, y: label.frame.maxY))
        
        enqueueOne()
    }
    func enqueueOne(){
        self.labelMark.isHidden = false
        self.labelMark.text = "Enqueuing"
        self.labelValue.isHidden = false
        self.labelValue.text = self.textField.text
        UIView.animate(withDuration: sumTime, animations: {
            self.labelValue.center = self.queueLabelArray[self.queueLabelArray.count-1].center
        }) { (_) in
            self.queueLabelArray[self.queueLabelArray.count-1].text = self.labelValue.text
            self.labelMark.isHidden = true
            self.labelValue.isHidden = true
            self.labelValue.frame =  CGRect(x: 130, y: 90, width: 80, height: 20)
            self.calculateUnitOfDistance(ta: (self.tailSubscript - 1))
            self.setUpSlash(type: .LabelAndLabelLine)
            self.enqueueTwo()
        }
    }
    
    func calculateUnitOfDistance(ta:Int){
        let y = 270 + Double(ta/4)*((Double(labelWDITH)+40)/2)
        let x = 20 + Double(ta%4)*(Double(labelWDITH)+20)
        unitDistanceY = (y-100)/(sumTime*10000)
        unitDistanceX = (x-180)/(sumTime*10000)
    }
    
    func enqueueTwo(){
        timeOne = Timer.scheduledTimer(timeInterval: 0.0001, target: self, selector:#selector(labelMove), userInfo: nil, repeats: true)
        timeTwo = Timer.scheduledTimer(timeInterval: 0.0001, target: self, selector: #selector(ActionTimeTwo), userInfo: nil, repeats: true)
    }
    @objc func labelMove(){
        numTimeOne = numTimeOne + 0.0001
        labelMoveAction(labelW: queueLabelArray[tailSubscript-1])
        if numTimeOne >= sumTime{
            numTimeOne = 0.00
            timeOne.invalidate()
        }
    }
    func labelMoveAction(labelW:CustomLabel){
        let x = labelW.frame.origin.x + CGFloat(unitDistanceX)
        let y = labelW.frame.origin.y + CGFloat(unitDistanceY)
        let w = labelW.frame.size.width
        let h = labelW.frame.size.height
        labelW.frame = CGRect(x: x, y: y, width: w, height: h)
        
        
        self.setPointOfLine(path: self.slashPathArray[0], shapeLayer: self.slashShapeLayerArray[0], move: CGPoint(x: self.headLabel.center.x, y: self.headLabel.center.y), addLine: CGPoint(x: self.queueLabelArray[0].frame.origin.x+self.labelWDITH/2, y: self.queueLabelArray[0].frame.origin.y))
        self.setPointOfLine(path: self.slashPathArray[1], shapeLayer: self.slashShapeLayerArray[1], move: CGPoint(x: self.tailLabel.center.x, y: self.tailLabel.center.y), addLine: CGPoint(x: self.queueLabelArray[self.tailSubscript-1].frame.origin.x+self.labelWDITH/2, y: self.queueLabelArray[self.tailSubscript-1].frame.origin.y+self.labelWDITH/2))
        
        if headSubscript < tailSubscript-1{
            setPointOfLine(path: pathArray[tailSubscript-2], shapeLayer: shapeLayerArray[tailSubscript-2], move: CGPoint(x: queueLabelArray[tailSubscript-2].frame.origin.x+labelWDITH, y: queueLabelArray[tailSubscript-2].frame.origin.y+labelWDITH/4), addLine: CGPoint(x: queueLabelArray[tailSubscript-1].frame.origin.x, y: queueLabelArray[tailSubscript-1].frame.origin.y+labelWDITH/4))
        }
        setPointOfLine(path: slashPathArray[2], shapeLayer: slashShapeLayerArray[2], move: CGPoint(x: labelW.frame.origin.x + labelW.frame.width*(3/4), y: labelW.frame.origin.y), addLine: CGPoint(x: labelW.frame.maxX, y: labelW.frame.maxY))
        
    }
    // 出队----------------------------------------------------------------
    @objc func ActionDequeue(){
        if tailSubscript != 0{
            dequeueOne()
            buttonIsEnabledFalse()
        }
        
        
        
    }
    func dequeueOne(){
        
        queueLabelArray[0].isHidden = true
        queueLabelArray.remove(at: 0)
        
        setPointOfLine(path: pathArray[0], shapeLayer: shapeLayerArray[0], move: CGPoint(x: 0, y: 0), addLine: CGPoint(x: 0, y: 0))
        pathArray.remove(at: 0)
        shapeLayerArray.remove(at: 0)
        tailSubscript = tailSubscript - 1
        
        if tailSubscript > headSubscript{
            self.setPointOfLine(path: self.slashPathArray[0], shapeLayer: self.slashShapeLayerArray[0], move: CGPoint(x: self.headLabel.center.x, y: self.headLabel.center.y), addLine: CGPoint(x: self.queueLabelArray[0].frame.origin.x+self.labelWDITH/2, y: self.queueLabelArray[0].frame.origin.y))
            timeOne = Timer.scheduledTimer(timeInterval: 0.0001, target: self, selector: #selector(dequeueTimeAction), userInfo: nil, repeats: true)
            
        }else{
            setPointOfLine(path: slashPathArray[0], shapeLayer: slashShapeLayerArray[0], move: CGPoint(x: headLabel.frame.minX, y: headLabel.frame.minY), addLine: CGPoint(x: headLabel.frame.maxX, y: headLabel.frame.maxY))
            setPointOfLine(path: slashPathArray[1], shapeLayer: slashShapeLayerArray[1], move: CGPoint(x: tailLabel.frame.minX, y: tailLabel.frame.minY), addLine: CGPoint(x: tailLabel.frame.maxX, y: tailLabel.frame.maxY))
            setPointOfLine(path: slashPathArray[2], shapeLayer: slashShapeLayerArray[2], move: CGPoint(x: 0, y: 0), addLine: CGPoint(x: 0, y: 0))
        }
        timeTwo = Timer.scheduledTimer(timeInterval: 0.0001, target: self, selector: #selector(ActionTimeTwo), userInfo: nil, repeats: true)
        
        
    }
    
    @objc func dequeueTimeAction(){
        for i in 0...queueLabelArray.count-1{
            moveLabelDequeue(ta: i)
            
        }
        numTimeOne = numTimeOne + 0.0001
        if numTimeOne >= sumTime{
            numTimeOne = 0.00
            timeOne.invalidate()
        }
    }
    
    func moveLabelDequeue(ta:Int){
        let lab = queueLabelArray[ta]
        if ta%4 == 3{
            let x = lab.frame.origin.x + CGFloat((3*(Double(labelWDITH) + 20))/(sumTime*10000))
            let y = lab.frame.origin.y - CGFloat((20+Double(labelWDITH)/2)/(sumTime*10000))
            let w = lab.frame.size.width
            let h = lab.frame.size.height
            lab.frame = CGRect(x: x, y: y, width: w, height: h)
        }else{
            let x = lab.frame.origin.x - CGFloat((Double(labelWDITH) + 20)/(sumTime*10000))
            let y = lab.frame.origin.y
            let w = lab.frame.size.width
            let h = lab.frame.size.height
            lab.frame = CGRect(x: x, y: y, width: w, height: h)
        }
        
        
        if ta < pathArray.count-1{
            setPointOfLine(path: pathArray[ta], shapeLayer: shapeLayerArray[ta], move: CGPoint(x: queueLabelArray[ta].frame.origin.x + labelWDITH, y: queueLabelArray[ta].frame.origin.y + labelWDITH/4), addLine: CGPoint(x: queueLabelArray[ta+1].frame.origin.x , y: queueLabelArray[ta+1].frame.origin.y + labelWDITH/4))
        }
        
         setPointOfLine(path: slashPathArray[2], shapeLayer: slashShapeLayerArray[2], move: CGPoint(x: queueLabelArray[tailSubscript-1].frame.origin.x + queueLabelArray[tailSubscript-1].frame.width*(3/4), y: queueLabelArray[tailSubscript-1].frame.origin.y), addLine: CGPoint(x: queueLabelArray[tailSubscript-1].frame.maxX, y: queueLabelArray[tailSubscript-1].frame.maxY))
        
        self.setPointOfLine(path: self.slashPathArray[0], shapeLayer: self.slashShapeLayerArray[0], move: CGPoint(x: self.headLabel.center.x, y: self.headLabel.center.y), addLine: CGPoint(x: self.queueLabelArray[0].frame.origin.x+self.labelWDITH/2, y: self.queueLabelArray[0].frame.origin.y))
        self.setPointOfLine(path: self.slashPathArray[1], shapeLayer: self.slashShapeLayerArray[1], move: CGPoint(x: self.tailLabel.center.x, y: self.tailLabel.center.y), addLine: CGPoint(x: self.queueLabelArray[self.tailSubscript-1].frame.origin.x+self.labelWDITH/2, y: self.queueLabelArray[self.tailSubscript-1].frame.origin.y+self.labelWDITH/2))
        
    }
    //计时器事件 控制按钮是否可点击
    @objc func ActionTimeTwo(){
        numTimeTwo = numTimeTwo + 0.0001
        if numTimeTwo >= sumTime{
            numTimeTwo = 0.00
            buttonIsEnabledTrue()
            timeTwo.invalidate()
        }
    }
    //    控制按钮是否可点击
    func buttonIsEnabledFalse(){
        buttonDequeue.isEnabled = false
        buttonEnqueue.isEnabled = false
        buttonClearQueue.isEnabled = false
        slider.isEnabled = false
    }
    func buttonIsEnabledTrue(){
        buttonDequeue.isEnabled = true
        buttonEnqueue.isEnabled = true
        buttonClearQueue.isEnabled = true
        slider.isEnabled = true
    }
    
    //    清除队列------------------------------------------------------------
    @objc func ActionClearQueue(){
        
        for i in queueLabelArray{
            i.isHidden = true
        }
        queueLabelArray.removeAll()
        for i in 0...pathArray.count-1{
            setPointOfLine(path: pathArray[i], shapeLayer: shapeLayerArray[i], move: CGPoint(x: 0, y: 0), addLine: CGPoint(x: 0, y: 0 ))
        }
        pathArray.removeAll()
        shapeLayerArray.removeAll()
        
        setPointOfLine(path: slashPathArray[0], shapeLayer: slashShapeLayerArray[0], move: CGPoint(x: headLabel.frame.minX, y: headLabel.frame.minY), addLine: CGPoint(x: headLabel.frame.maxX, y: headLabel.frame.maxY))
        setPointOfLine(path: slashPathArray[1], shapeLayer: slashShapeLayerArray[1], move: CGPoint(x: tailLabel.frame.minX, y: tailLabel.frame.minY), addLine: CGPoint(x: tailLabel.frame.maxX, y: tailLabel.frame.maxY))
        setPointOfLine(path: slashPathArray[2], shapeLayer: slashShapeLayerArray[2], move: CGPoint(x: 0, y: 0), addLine: CGPoint(x: 0, y: 0))
        
        tailSubscript = 0
        headSubscript = 0
    }
    
    //控制每一步动画总时间---------------------------------------------------
    @objc func ActionSliderValueChange(){
        if Double(slider.value) <= 0.0001{
            sumTime = 0.0001
        }else{
            sumTime = Double(slider.value)
        }
        
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
